package com.poizon.infrastructure.idem.starter.redis;

import cn.hutool.core.util.StrUtil;
import com.poizon.infrastructure.idem.core.util.impl.AbstractRepeatedSubmitUtil;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.concurrent.TimeUnit;


/**
 * 工具类/幂等
 */
@Slf4j
@AllArgsConstructor
public class RepeatedSubmitUtil extends AbstractRepeatedSubmitUtil {
    protected StringRedisTemplate redisTemplate;

    /**
     * 防重提交(不存储返回结果)
     *
     * @param operationKey 防重提交key 例如= 全局requestId | 业务键1=业务键2
     * @param expireTime   防重提交键 过期时间
     */
    @SneakyThrows
    @Override
    protected void executeRepeatedSubmitImpl(@NotBlank String operationKey, @NotNull Long expireTime, @NotNull Runnable serviceRunnable, @NotNull Runnable repeatedRunnable, @NotNull TimeUnit timeUnit) {
        // 组装幂等键
        String idemKey = Get.getIdemKey(operationKey);

        // 防重标识设置
        Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent(idemKey, "1", expireTime, timeUnit);

        if (Boolean.TRUE.equals(lockAcquired)) {
            try {
                serviceRunnable.run();
            } catch (Exception e) {
                try {
                    redisTemplate.delete(idemKey);
                } catch (Exception e1) {
                    log.error(StrUtil.format("[通用幂等框架] 防重业务执行失败,操作标识={},防重键回退失败，请人工手动删除防重键", operationKey), e);
                }
                // 抛出业务异常
                throw e;
            }
        } else {
            if (repeatedRunnable != null) {
                repeatedRunnable.run();
            }
            throw new RuntimeException("请勿重复提交");
        }
    }
}
